home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / gcore / ds3100.md / gcore.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-25  |  13.9 KB  |  491 lines

  1. /* 
  2.  * gcore.c --
  3.  *
  4.  *    This file contains a program that will produce a Unix
  5.  *    style core dump of a process.
  6.  *    See the man page for details on what it does.
  7.  *
  8.  * Copyright 1988 Regents of the University of California
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /sprite/src/cmds/gcore/RCS/gcore.c,v 1.3 91/10/25 10:28:35 jhh Exp $ SPRITE (Berkeley)";
  20. #endif not lint
  21.  
  22. #include <ctype.h>
  23. #include <option.h>
  24. #include <status.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <signal.h>
  29. #include <sys/types.h>
  30. #include <sys/file.h>
  31. #include <kernel/mach.h>
  32. #include <kernel/proc.h>
  33. #include <kernel/procMach.h>
  34. #include <a.out.h>
  35. #include <errno.h>
  36.  
  37. extern char *sys_errlist[];
  38.  
  39. #include "gcore.h"
  40.  
  41.  
  42. Boolean    debug = FALSE;            /* Output debugging info. */
  43. char    *outFilePrefix = "core";    /* Coredump output file. */
  44. #ifdef SAFETY
  45. Boolean    dumpRunningProcess = FALSE;    /* If true, an attempt is made to
  46.                      * dump process not in the debugger.
  47.                      */
  48. #else
  49. Boolean    dumpRunningProcess = TRUE;    /* If true, an attempt is made to
  50.                      * dump process not in the debugger.
  51.                      */
  52. #endif    
  53.  
  54. int    debugSignal = SIGTRAP;        /* Signal to bump process into the
  55.                      * debugger with.
  56.                      */
  57. Boolean killProcess = FALSE;        /* Kill process after dump. */
  58.  
  59. Option optionArray[] = {
  60.    {OPT_DOC,    (char *) NULL,    (char *) NULL,
  61.         "This program generates a core dump of a process.\n Synopsis:  \"gcore [options] pid [pid pid...]\"\nOptions are:"},
  62.    {OPT_STRING, "o", (char *) &outFilePrefix, "Prefix string for dump files."},
  63. #ifdef SAFETY
  64.    {OPT_TRUE,   "f", (char *) &dumpRunningProcess, 
  65.     "The dump the process evening if it is running."},
  66. #endif
  67.    {OPT_TRUE,   "k", (char *) &killProcess, "Kill processes after the dump."},  
  68.    {OPT_INT,    "s", (char *) &debugSignal, "Signal number to stop processes."},
  69.    {OPT_TRUE,    "d", (char *) &debug, "Output program debugging info."},
  70. };
  71.  
  72. /*
  73.  * Forward procedure declarations.
  74.  */
  75. static Boolean    DumpCore();
  76.  
  77.  
  78. /*
  79.  *----------------------------------------------------------------------
  80.  *
  81.  * main --
  82.  *
  83.  *    The main program for gcore.
  84.  *
  85.  * Results:
  86.  *    None.
  87.  *
  88.  * Side effects:
  89.  *    Writes output to sepcified file.
  90.  *
  91.  *----------------------------------------------------------------------
  92.  */
  93.  
  94. main(argc, argv)
  95.     int argc;        /* Number of command-line arguments. */
  96.     char **argv;    /* Values of command-line arguments. */
  97. {
  98.     int numCantDump;
  99.     int    i;
  100.  
  101.     argc = Opt_Parse(argc, argv, optionArray, Opt_Number(optionArray),0);
  102.     if (argc < 2) {
  103.     (void) fprintf(stderr,"Usage: %s [options] pid ...\n",PROGRAM_NAME);
  104.     exit(1);
  105.     } 
  106.     numCantDump = 0;
  107.     for (i = 1; i < argc; i++) {
  108.         int    pid;
  109.     char    *pidString;
  110.     char    *outFileName = malloc(strlen(outFilePrefix)+16);
  111.  
  112.     pidString = argv[i];
  113.         /*
  114.      * Convert the string pidString into an integer pid.
  115.      */
  116.     {
  117.         char    *endPtr;
  118.  
  119.         pid = strtoul(pidString, &endPtr, 16);
  120.         if (debug) {
  121.           fprintf(stderr, "%s %d\n", pidString, pid);
  122.         }
  123.         if (endPtr == pidString) {
  124.         (void) fprintf(stderr,"%s: Bad process id \"%s\"; ignoring\n", 
  125.             PROGRAM_NAME,  pidString);
  126.         numCantDump++;
  127.         continue;
  128.         }
  129.     }
  130.     (void) sprintf(outFileName,"%s.%s",outFilePrefix,pidString);
  131.         if (DumpCore(pid, outFileName, pidString)) {
  132.         (void) printf("%s: %s dumped\n",PROGRAM_NAME,outFileName);
  133.     } else {
  134.         numCantDump++;
  135.     }
  136.     }
  137.     exit(numCantDump);
  138. }
  139.  
  140.  
  141.  
  142. /*
  143.  *----------------------------------------------------------------------
  144.  *
  145.  * GetProgramName --
  146.  *
  147.  *    Find the program name in the command string.
  148.  *
  149.  *    The routine takes a command string and returns the name of the 
  150.  *    program used in the command.  A command is assume to be a string
  151.  *    of the form:
  152.  *        commandPathname    arg1 arg2 arg3 ....
  153.  *    The program name is the file name of the exec file in the command.
  154.  *
  155.  * Results:
  156.  *    Nothing.
  157.  *
  158.  * Side effects:
  159.  *      None.
  160.  *
  161.  *----------------------------------------------------------------------
  162.  */
  163.  
  164. void 
  165. GetProgramName(argString,programName)
  166.     char    *argString;    /* Argument string of process. */
  167.     char    *programName;    /* Area to place program name. */
  168. {
  169.     register char    *endPtr, *startPtr;
  170.  
  171.     /*
  172.      * Strip any leading blanks.
  173.      */
  174.     while (*argString == ' ') {
  175.     argString++;
  176.     }
  177.     /*
  178.      * Locate the end of the program string. This is either the first blank
  179.      * or end of string.
  180.      */
  181.     endPtr = strchr(argString,' ');
  182.     if (endPtr == NULL) {
  183.     endPtr = argString + strlen(argString);
  184.     }
  185.     if (endPtr == argString) {
  186.     *programName = 0;
  187.     return;
  188.     }
  189.     /*
  190.      * From the end of the program string, find the beginning by working 
  191.      * backwards until the first '/' or beginning of string is found.
  192.      */
  193.     for (startPtr = endPtr - 1; startPtr > argString; startPtr--) {
  194.     if (*startPtr == '/') {
  195.         startPtr++;
  196.         break;
  197.     }
  198.     }
  199.     { 
  200.     int    len = endPtr - startPtr;
  201.     bcopy(startPtr, programName, len);
  202.     programName[len] = 0;
  203.     }
  204. }
  205.  
  206.  
  207.  
  208. /*
  209.  *----------------------------------------------------------------------
  210.  *
  211.  *  DumpCore --
  212.  *
  213.  *      Dump the core image of the specified process.
  214.  *
  215.  * Results:
  216.  *    True if dump succeeded, false otherwise.
  217.  *
  218.  * Side effects:
  219.  *      Core image is dumped to a file.
  220.  *
  221.  *----------------------------------------------------------------------
  222.  */
  223. static Boolean
  224. DumpCore(pid,coreFileName,pidString)
  225.     int     pid;            /* Process id to dump. */
  226.     char     *coreFileName;    /* Name of core file to create. */
  227.     char    *pidString;    /* String name of pid - use only for message. */
  228. {
  229.     char        *argString;    /* Argument string of process. */
  230.     char        *argStringProgram;
  231.     struct user        coreHeader;    /* Header written to coreFile. */
  232.     int            segSize[NUM_SEGMENTS];
  233.     FILE        *coreFile;    /* Core file. */
  234.     int            procState, procOrigState;
  235.     int            sigState;
  236.     Boolean        retVal = FALSE;
  237.     ProcExecHeader      header;
  238.     /*
  239.      * Find the status and argument string of the process. 
  240.      */
  241.     argString = malloc(MAX_ARG_STRING_SIZE);
  242.     /*
  243.      * Find and record the original state of this process. 
  244.      */
  245.     sigState = debugSignal;
  246.     procOrigState = FindProcess(pid,argString,segSize,&sigState);
  247.     /*
  248.      * Get pcb for process.
  249.      */
  250.     if (procOrigState == NOT_FOUND_STATE) {
  251.      (void) fprintf(stderr, "%s: Process id %s not found.\n",
  252.             PROGRAM_NAME, pidString );
  253.     return (FALSE);
  254.     }
  255.     /*
  256.      * Insure that we can open the coreFile before signalling the process.
  257.      */
  258.      coreFile = fopen(coreFileName,"w");
  259.      if (coreFile == (FILE *) NULL) {
  260.      (void) fprintf(stderr,
  261.          "%s: Can't open %s: %s\n",PROGRAM_NAME,coreFileName,
  262.         sys_errlist[errno]);
  263.      return (FALSE);
  264.      }
  265.     /*
  266.      * If the process is not already in the DEBUG state, put it there.
  267.      */
  268.     if (procOrigState != DEBUG_STATE) {
  269.     /*
  270.      * Check to see if SAFETY is on.
  271.      */
  272.     if (!dumpRunningProcess) {
  273.         (void) fprintf(stderr,
  274.         "%s: Process id %s is running, must use -f to dump.\n",
  275.         PROGRAM_NAME, pidString);
  276.         (void) fclose(coreFile); (void) unlink(coreFileName);
  277.         return (FALSE);
  278.     }
  279.     /*
  280.      * See if the debugSignal is being held, ignored, or handled.
  281.      */
  282.     if (sigState != 0) {
  283.         char    *problem;
  284.  
  285.         if (sigState & SIG_IGNORING) {
  286.         problem = "ignoring";
  287.         } else if (sigState & SIG_HANDLING) {
  288.         problem = "handling";
  289.         } else if (sigState & SIG_HOLDING) {
  290.         problem = "holding";
  291.         } else {
  292.         problem = NULL;
  293.         }
  294.         if (problem) { 
  295.         (void) fprintf(stderr,
  296.             "%s: Process %s is %s signal %d; can't dump.\n",
  297.             PROGRAM_NAME, pidString, problem, debugSignal);
  298.         (void) fclose(coreFile); (void) unlink(coreFileName);
  299.         return (FALSE);
  300.         }
  301.     }
  302.     /*
  303.      * Try bumping the process into the debugger. This will fail if the
  304.      * user can't signal the process.
  305.      */
  306.     if(kill(pid,debugSignal) < 0) {
  307.         (void) fprintf(stderr,
  308.             "%s: Can't signal process %s with signal %d: %s\n",
  309.             PROGRAM_NAME, pidString, debugSignal,sys_errlist[errno]);
  310.         (void) fclose(coreFile); (void) unlink(coreFileName);
  311.         return (FALSE);
  312.      } 
  313.      (void) sleep(1);
  314.      procState = FindProcess(pid,argString,segSize,(int *) 0);
  315.      /* 
  316.       * If process is still not in the debug state, trying giving it a
  317.       * SIGCONT.  This appears to be necessary to get suspended process
  318.       * into the debug state.
  319.       */
  320.      if (procState == SUSPEND_STATE) {
  321.         (void) kill(pid,SIGCONT);
  322.             (void) sleep(1);
  323.         procState = FindProcess(pid,argString,segSize,(int *) 0);
  324.      }
  325.      if (procState != DEBUG_STATE) {
  326.          if (procState == NOT_FOUND_STATE) {
  327.         (void) fprintf(stderr,
  328.             "%s: Process id %s disappeared after signal %d, sorry.\n",
  329.             PROGRAM_NAME, pidString,debugSignal);
  330.         } else {
  331.         (void) fprintf(stderr,
  332.             "%s: Process %s wont stop for signal %d.\n",
  333.             PROGRAM_NAME, pidString, debugSignal);
  334.         }
  335.         (void) fclose(coreFile); (void) unlink(coreFileName);
  336.         return (FALSE);
  337.     }
  338.     }
  339.     /*
  340.      * Attach the process using the debugger interface. 
  341.      */
  342.     if (!AttachProcess(pid)) {
  343.     (void) fprintf(stderr,
  344.            "%s: Can't attach process %s\n",PROGRAM_NAME, pidString);
  345.     (void) fclose(coreFile); (void) unlink(coreFileName);
  346.     return(FALSE);
  347.     }
  348.  
  349.     /* Find the program name from the argument string. */
  350.  
  351.     argStringProgram = malloc(strlen(argString)+1);
  352.     GetProgramName(argString,argStringProgram);
  353.  
  354.     /*
  355.      * Fill in the core file header with our best guess.
  356.      */
  357. /*     coreHeader.c_magic = CORE_MAGIC;
  358.        coreHeader.c_len = sizeof(struct user);*/
  359.     if (!ReadStopInfoFromProcess(pid,&coreHeader.u_error,&coreHeader.u_pcb)) {
  360.        (void) fprintf(stderr,"%s: Can't read regs of process %s\n",PROGRAM_NAME,
  361.                         pidString);
  362.             (void) fclose(coreFile); 
  363.        goto errout;
  364.      }
  365.     /*
  366.      * Fill in the exec file header with our best guesses.
  367.      */
  368.     header.fileHeader = *((ProcFileHeader *)malloc(sizeof(ProcFileHeader)));
  369.     header.aoutHeader = *((ProcAOUTHeader *)malloc(sizeof(ProcAOUTHeader)));
  370.     bzero((char *)&header,sizeof(header));
  371.     header.fileHeader.magic = ZMAGIC;
  372.     header.fileHeader.numSections = 3;
  373.     header.aoutHeader.magic = ZMAGIC;
  374.     header.aoutHeader.codeSize = segSize[TEXT_SEG];
  375.     header.aoutHeader.heapSize = segSize[DATA_SEG];
  376.     header.aoutHeader.verStamp = 23;
  377.     
  378.     coreHeader.u_tsize = segSize[TEXT_SEG]/PAGSIZ;
  379.     coreHeader.u_ar0 = 0;
  380.       (void) strncpy(coreHeader.u_comm,argStringProgram,MAXCOMLEN);
  381.  
  382.      /*
  383.       * Write empty coreHeader to be filled in later. This reserve space
  384.       * in the output file for the header.
  385.       */
  386.      if (fwrite((char *)&coreHeader,sizeof(coreHeader),1,coreFile) != 1) {
  387.      (void) fprintf(stderr,"%s: Can't write file %s: %s\n",PROGRAM_NAME,
  388.         coreFileName,sys_errlist[errno]);
  389.      (void) fclose(coreFile);
  390.      goto errout;
  391.      }
  392.  
  393.     /*
  394.      * Follow the coreHeader with the data segment
  395.      */
  396.      {
  397. /*       bcopy((char *)&coreHeader.c_aouthdr,(char *)&header, sizeof(header));*/
  398.        if (fseek(coreFile,8192,0) < 0) {
  399.      (void) fprintf(stderr,
  400.         "%s: Can't find start of data segment: %s\n",PROGRAM_NAME,
  401.         sys_errlist[errno]);
  402.        }
  403.        coreHeader.u_dsize = (XferSegmentFromProcess(pid,(unsigned int)(1<<28),coreFile))/PAGSIZ;
  404.      }
  405.      if (coreHeader.u_dsize <= 0) {
  406.      (void) fprintf(stderr,"%s: Can't read data segment.\n",PROGRAM_NAME);
  407.      (void) fclose(coreFile);
  408.      goto errout;
  409.      }
  410.  
  411.     /*
  412.      * And then the stack segment starting with at the stack pointer.
  413.      */
  414.      coreHeader.u_ssize = (XferSegmentFromProcess(pid,
  415.                    (unsigned int) coreHeader.u_pcb.pcb_regs[29], coreFile))/PAGSIZ;
  416.      if (coreHeader.u_ssize <= 0) {
  417.      (void) fprintf(stderr,"%s: Can't read stack segment.\n",PROGRAM_NAME);
  418.      (void) fclose(coreFile);
  419.      goto errout;
  420.      }
  421.      /*
  422.       * Now rewrite the coreFile header with the new data and stack segment
  423.       * sizes.
  424.       */
  425.      if (fseek(coreFile,0,0) < 0) {
  426.      (void) fprintf(stderr,
  427.         "%s: Can't rewrite file %s header: %s\n",PROGRAM_NAME,
  428.         coreFileName,sys_errlist[errno]);
  429.      }
  430.      if (fwrite((char *)&coreHeader,sizeof(coreHeader),1,coreFile) != 1) {
  431.      (void) fprintf(stderr,"%s: Can't write %s : %s\n",PROGRAM_NAME,
  432.         coreFileName,sys_errlist[errno]);
  433.      (void) fclose(coreFile);
  434.      goto errout;
  435.      }
  436.      if (fclose(coreFile) != 0)  {
  437.      (void) fprintf(stderr,"%s: Error closing %s : %s\n",PROGRAM_NAME,
  438.         coreFileName,sys_errlist[errno]);
  439.      }
  440.      retVal = TRUE;
  441.      /* 
  442.       * Did the user want the process dead?
  443.       */
  444.      if (killProcess && (kill(pid,SIGKILL) < 0)) {
  445.      (void) fprintf(stderr,
  446.             "%s: Can't kill process %s: %s\n",
  447.             PROGRAM_NAME, pidString, sys_errlist[errno]);
  448.      }
  449.  errout:
  450.      /*
  451.       * Detach the debugger from the process. If the process was in
  452.       * the suspend state the detach will start it running again. 
  453.       * The current thinking is that this is not good so we leave
  454.       * suspended processes in the debugger.
  455.       */
  456.      if (killProcess || ! ( (procOrigState == SUSPEND_STATE) ||
  457.                 (procOrigState == DEBUG_STATE))) {
  458.      static char *procStateNames[] = STATE_NAMES;
  459.      (void) DetachProcess(pid);
  460.      (void) sleep(1);
  461.      procState = FindProcess(pid,argString,(int *) 0,(int *) 0);
  462.      /*
  463.       * If we didn't want it dead and it died?
  464.       */
  465.      if (!killProcess && (procState == NOT_FOUND_STATE)) {
  466.         (void) fprintf(stderr,
  467.         "%s: Warning: Process %s disappeared after dump, sorry.\n",
  468.         PROGRAM_NAME, pidString);
  469.      } else if (killProcess && (procState != NOT_FOUND_STATE)) {
  470. #ifdef notdef
  471.     /*
  472.      * This doesn't appear to work.
  473.      */
  474.         (void) fprintf(stderr,
  475.         "%s: Warning: Process %s didn't die.\n",PROGRAM_NAME, 
  476.          pidString);
  477. #endif
  478.      } else if (procState != procOrigState) {
  479.          (void) fprintf(stderr,
  480.         "%s: Warning: Process %s new state is %s was %s\n",
  481.         PROGRAM_NAME, pidString,procStateNames[procState],
  482.         procStateNames[procOrigState]);
  483.      } 
  484.      }
  485.      if (!retVal) {
  486.      (void) unlink(coreFileName);
  487.      (void) fclose(coreFile);
  488.      }
  489.      return (retVal);
  490. }
  491.